home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP09.ZIP / CHAP09 / PATRON / PAGEWIN.CPP < prev    next >
C/C++ Source or Header  |  1993-06-17  |  23KB  |  840 lines

  1. /*
  2.  * PAGEWIN.CPP
  3.  * Modifications for Chapter 9
  4.  *
  5.  * Window procedure for the Pages window and support functions.  This
  6.  * window manages its own scrollbars and viewport and provides
  7.  * printing capabilities as well.  The public CPages::Print lives here.
  8.  *
  9.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Software Design Engineer
  12.  * Microsoft Systems Developer Relations
  13.  *
  14.  * Internet  :  kraigb@microsoft.com
  15.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  16.  */
  17.  
  18.  
  19.  
  20. #include "patron.h"
  21.  
  22.  
  23. extern HWND g_hDlgPrint;
  24. extern BOOL g_fCancelPrint;
  25.  
  26.  
  27. /*
  28.  * PagesWndProc
  29.  *
  30.  * Purpose:
  31.  *  Window procedure for the Pages window.
  32.  */
  33.  
  34. LRESULT __export FAR PASCAL PagesWndProc(HWND hWnd, UINT iMsg
  35.     , WPARAM wParam, LPARAM lParam)
  36.     {
  37.     LPCPages        ppg;
  38.     PAINTSTRUCT     ps;
  39.     HDC             hDC;
  40.     int             iPos, iTmp;
  41.     int             iMin, iMax;
  42.     UINT            idScroll;
  43.     BOOL            fDirty=FALSE;
  44.  
  45.     ppg=(LPCPages)GetWindowLong(hWnd, PAGEWL_STRUCTURE);
  46.  
  47.     switch (iMsg)
  48.         {
  49.         case WM_CREATE:
  50.             ppg=(LPCPages)((LPCREATESTRUCT)lParam)->lpCreateParams;
  51.             SetWindowLong(hWnd, PAGEWL_STRUCTURE, (LONG)ppg);
  52.  
  53.             ppg->m_hWnd=hWnd;
  54.             break;
  55.  
  56.  
  57.         case WM_PAINT:
  58.             /*
  59.              * If there is currently a drag-rectangle showing, then
  60.              * remove it before painting.  This insures that painting
  61.              * doesn't blast part of that rectangle away such that when
  62.              * we draw it next, garbage is left around.
  63.              */
  64.             if (ppg->m_fDragRectShown)
  65.                 ppg->DrawDropTargetRect(NULL, NULL);
  66.  
  67.             hDC=BeginPaint(hWnd, &ps);
  68.  
  69.             //Draw only if we have a page to show.
  70.             if (0!=ppg->m_cPages)
  71.                 ppg->Draw(hDC, FALSE, FALSE);
  72.  
  73.             EndPaint(hWnd, &ps);
  74.  
  75.             //Turn the rectangle back on, if necessary.
  76.             if (ppg->m_fDragRectShown)
  77.                 ppg->DrawDropTargetRect(NULL, NULL);
  78.  
  79.             break;
  80.  
  81.  
  82.         case WM_HSCROLL:
  83.         case WM_VSCROLL:
  84.             idScroll=(WM_HSCROLL==iMsg) ? SB_HORZ : SB_VERT;
  85.  
  86.             iPos=GetScrollPos(hWnd, idScroll);
  87.             iTmp=iPos;
  88.             GetScrollRange(hWnd, idScroll, &iMin, &iMax);
  89.  
  90.             switch (wParam)
  91.                 {
  92.                 case SB_LINEUP:     iPos -= 20;  break;
  93.                 case SB_PAGEUP:     iPos -=100;  break;
  94.                 case SB_LINEDOWN:   iPos += 20;  break;
  95.                 case SB_PAGEDOWN:   iPos +=100;  break;
  96.  
  97.                 case SB_THUMBPOSITION:
  98.                     iPos=ScrollThumbPosition(wParam, lParam);
  99.                     break;
  100.  
  101.                 //We don't want scrolling on this message.
  102.                 case SB_THUMBTRACK:
  103.                     return 0L;
  104.                 }
  105.  
  106.             iPos=max(iMin, min(iPos, iMax));
  107.  
  108.             if (iPos!=iTmp)
  109.                 {
  110.                 //Set the new position and scroll the window as necessary.
  111.                 SetScrollPos(hWnd, idScroll, iPos, TRUE);
  112.  
  113.                 if (SB_HORZ==idScroll)
  114.                     {
  115.                     ppg->m_xPos=iPos;
  116.                     ScrollWindow(hWnd, iTmp-iPos, 0, NULL, NULL);
  117.                     }
  118.                 else
  119.                     {
  120.                     ppg->m_yPos=iPos;
  121.                     ScrollWindow(hWnd, 0, iTmp-iPos, NULL, NULL);
  122.                     }
  123.                 }
  124.  
  125.             break;
  126.  
  127.         //CHAPTER9MOD
  128.         case WM_RBUTTONDOWN:
  129.             if (NULL==ppg->m_pPageCur)
  130.                 break;
  131.  
  132.             fDirty=ppg->m_pPageCur->OnRightDown(wParam
  133.                 , LOWORD(lParam), HIWORD(lParam));
  134.             break;
  135.         //End CHAPTER9MOD
  136.  
  137.         case WM_LBUTTONDOWN:
  138.             if (NULL==ppg->m_pPageCur)
  139.                 break;
  140.  
  141.             fDirty=ppg->m_pPageCur->OnLeftDown(wParam
  142.                 , LOWORD(lParam), HIWORD(lParam));
  143.             break;
  144.  
  145.         case WM_LBUTTONUP:
  146.             if (NULL==ppg->m_pPageCur)
  147.                 break;
  148.  
  149.             fDirty=ppg->m_pPageCur->OnLeftUp(wParam
  150.                 , LOWORD(lParam), HIWORD(lParam));
  151.             break;
  152.  
  153.         case WM_LBUTTONDBLCLK:
  154.             if (NULL==ppg->m_pPageCur)
  155.                 break;
  156.  
  157.             fDirty=ppg->m_pPageCur->OnLeftDoubleClick(wParam, LOWORD(lParam)
  158.                 , HIWORD(lParam));
  159.             break;
  160.  
  161.         case WM_MOUSEMOVE:
  162.             if (NULL==ppg->m_pPageCur)
  163.                 break;
  164.  
  165.             ppg->m_pPageCur->OnMouseMove(wParam, LOWORD(lParam)
  166.                 , HIWORD(lParam));
  167.             break;
  168.  
  169.         case WM_NCHITTEST:
  170.             if (NULL!=ppg->m_pPageCur)
  171.                 {
  172.                 //This just saves information in the page for OnSetCursor
  173.                 ppg->m_pPageCur->OnNCHitTest(LOWORD(lParam)
  174.                     , HIWORD(lParam));
  175.                 }
  176.  
  177.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  178.  
  179.         case WM_SETCURSOR:
  180.             if (NULL!=ppg->m_pPageCur)
  181.                 {
  182.                 if (ppg->m_pPageCur->OnSetCursor(LOWORD(lParam)))
  183.                     break;
  184.                 }
  185.  
  186.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  187.  
  188.         default:
  189.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  190.         }
  191.  
  192.     ppg->m_fDirty |= fDirty;
  193.     return 0L;
  194.     }
  195.  
  196.  
  197.  
  198.  
  199.  
  200. /*
  201.  * RectConvertMappings
  202.  *
  203.  * Purpose:
  204.  *  Converts the contents of a rectangle from device to logical
  205.  *  coordinates where the hDC defines the logical coordinates.
  206.  *
  207.  * Parameters:
  208.  *  pRect           LPRECT containing the rectangle to convert.
  209.  *  hDC             HDC describing the logical coordinate system.
  210.  *                  if NULL, uses a screen DC in MM_LOMETRIC.
  211.  *  fToDevice       BOOL TRUE to convert from uConv to device,
  212.  *                  FALSE to convert device to uConv.
  213.  *
  214.  * Return Value:
  215.  *  None
  216.  */
  217.  
  218. void RectConvertMappings(LPRECT pRect, HDC hDC, BOOL fToDevice)
  219.     {
  220.     POINT   rgpt[2];
  221.     BOOL    fSysDC=FALSE;
  222.  
  223.     if (NULL==pRect)
  224.         return;
  225.  
  226.     rgpt[0].x=pRect->left;
  227.     rgpt[0].y=pRect->top;
  228.     rgpt[1].x=pRect->right;
  229.     rgpt[1].y=pRect->bottom;
  230.  
  231.     if (NULL==hDC)
  232.         {
  233.         hDC=GetDC(NULL);
  234.         SetMapMode(hDC, MM_LOMETRIC);
  235.         fSysDC=TRUE;
  236.         }
  237.  
  238.     if (fToDevice)
  239.         LPtoDP(hDC, rgpt, 2);
  240.     else
  241.         DPtoLP(hDC, rgpt, 2);
  242.  
  243.     if (fSysDC)
  244.         ReleaseDC(NULL, hDC);
  245.  
  246.     pRect->left=rgpt[0].x;
  247.     pRect->top=rgpt[0].y;
  248.     pRect->right=rgpt[1].x;
  249.     pRect->bottom=rgpt[1].y;
  250.  
  251.     return;
  252.     }
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260. /*
  261.  * CPages::Draw
  262.  *
  263.  * Purpose:
  264.  *  Paints the current page in the pages window.
  265.  *
  266.  * Parameters:
  267.  *  hDC             HDC to draw on, could be a metafile or printer DC or
  268.  *                  any other type of DC.
  269.  *  fNoColor        BOOL indicating if we should use screen colors or
  270.  *                  printer colos (B&W).  Objects are printed as-is, however.
  271.  *                  This is TRUE for printer DCs or print preview.
  272.  *  fPrinter        BOOL indicating if this is a printer DC in which case
  273.  *                  we eliminate some of the fancy drawing, like shadows on
  274.  *                  the page and so forth.
  275.  *
  276.  * Return Value:
  277.  *  None
  278.  */
  279.  
  280. void CPages::Draw(HDC hDC, BOOL fNoColor, BOOL fPrinter)
  281.     {
  282.     RECT            rc, rcT;
  283.     UINT            uMM;
  284.     HPEN            hPen;
  285.     HBRUSH          hBrush;
  286.     HGDIOBJ         hObj1, hObj2;
  287.     COLORREF        cr;
  288.     char            szTemp[20];
  289.     UINT            cch;
  290.     DWORD           dwExt;
  291.     LPPAGE          pPage;
  292.     RECT            rcPos;
  293.  
  294.     //Make sure the DC is in LOMETRIC
  295.     uMM=SetMapMode(hDC, MM_LOMETRIC);
  296.  
  297.     if (!fPrinter)
  298.         {
  299.         /*
  300.          * We maintain a 6mm border around the page on the screen besides
  301.          * 12.7mm margins.  We also have to account for the scroll position
  302.          * with m_*Pos which are in pixels so we have to convert them.
  303.          */
  304.         SetRect(&rcPos, m_xPos, m_yPos, 0, 0);
  305.         RectConvertMappings(&rcPos, hDC, FALSE);
  306.  
  307.         rc.left  = LOMETRIC_BORDER-rcPos.left;
  308.         rc.top   =-LOMETRIC_BORDER-rcPos.top;
  309.         }
  310.     else
  311.         {
  312.         /*
  313.          * We define the corner of the printed paper at a negative
  314.          * offset so rc.right and rc.bottom come out right below.
  315.          */
  316.         SetRect(&rc, -(int)m_xMarginLeft, m_yMarginTop, 0, 0);
  317.         }
  318.  
  319.     rc.right =rc.left+(UINT)m_cx+(UINT)(m_xMarginLeft+m_xMarginRight);
  320.     rc.bottom=rc.top -(UINT)m_cy-(UINT)(m_yMarginTop+m_yMarginBottom);
  321.  
  322.     //Draw a rectangle filled with the window color to show the page.
  323.     if (!fPrinter)
  324.         {
  325.         if (fNoColor)
  326.             {
  327.             //Black frame, white box for printed colors.
  328.             hPen  =CreatePen(PS_SOLID, 0, RGB(0,0,0));
  329.             hBrush=CreateSolidBrush(RGB(255, 255, 255));
  330.             }
  331.         else
  332.             {
  333.             //Normal colors on display
  334.             hPen  =CreatePen(PS_SOLID, 0, GetSysColor(COLOR_WINDOWFRAME));
  335.             hBrush=CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  336.             }
  337.  
  338.         hObj1=SelectObject(hDC, hPen);
  339.         hObj2=SelectObject(hDC, hBrush);
  340.  
  341.         //Paper boundary
  342.         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom+1);
  343.  
  344.         /*
  345.          * Draw a shadow on the *visual* bottom and right edges .5mm wide.
  346.          * If the button shadow color and workspace colors match, then
  347.          * use black.  We always use black when printing as well.
  348.          */
  349.         if (fNoColor)
  350.             cr=RGB(0,0,0);
  351.         else
  352.             {
  353.             cr=GetSysColor(COLOR_BTNSHADOW);
  354.  
  355.             if (GetSysColor(COLOR_APPWORKSPACE)==cr)
  356.                 cr=RGB(0,0,0);
  357.             }
  358.  
  359.         cr=SetBkColor(hDC, cr);
  360.         SetRect(&rcT, rc.left+5, rc.bottom, rc.right+5, rc.bottom-5);
  361.         ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcT, NULL, 0, NULL);
  362.  
  363.         SetRect(&rcT, rc.right, rc.top-5, rc.right+5, rc.bottom-5);
  364.         ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcT, NULL, 0, NULL);
  365.         SetBkColor(hDC, cr);
  366.  
  367.         SelectObject(hDC, hObj1);
  368.         SelectObject(hDC, hObj2);
  369.         DeleteObject(hBrush);
  370.         DeleteObject(hPen);
  371.         }
  372.  
  373.     //Write the page number in the lower left corner
  374.     if (!fNoColor)
  375.         {
  376.         SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  377.         SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  378.         }
  379.  
  380.     //Write the page number in our page font.
  381.     cch=wsprintf(szTemp, "Page %d", m_iPageCur+1);
  382.  
  383.     hObj1=SelectObject(hDC, m_hFont);
  384.     dwExt=GetTextExtent(hDC, szTemp, cch);
  385.  
  386.     TextOut(hDC, rc.left+m_xMarginLeft
  387.         , rc.bottom+m_yMarginBottom+HIWORD(dwExt), szTemp, cch);
  388.  
  389.     SelectObject(hDC, hObj1);
  390.  
  391.     //Rectangle to show border.
  392.     MoveTo(hDC, rc.left+m_xMarginLeft,   rc.top-m_yMarginTop);
  393.     LineTo(hDC, rc.left+m_xMarginLeft,   rc.bottom+m_yMarginBottom);
  394.     LineTo(hDC, rc.right-m_xMarginRight, rc.bottom+m_yMarginBottom);
  395.     LineTo(hDC, rc.right-m_xMarginRight, rc.top-m_yMarginTop);
  396.     LineTo(hDC, rc.left+m_xMarginLeft,   rc.top-m_yMarginTop);
  397.  
  398.     /*
  399.      * Go draw the objects on this page.  If the page is not open, we
  400.      * open it anyway.  If it is already open, then opening again will
  401.      * bump it's reference count, so the Close in ineffectual.
  402.      */
  403.     if (FPageGet(m_iPageCur, &pPage, TRUE))
  404.         {
  405.         if (!fPrinter)
  406.             pPage->Draw(hDC, rcPos.left, rcPos.top, fNoColor, fPrinter);
  407.         else
  408.             pPage->Draw(hDC, 0, 0, fNoColor, fPrinter);
  409.  
  410.         pPage->Close(FALSE);
  411.         }
  412.  
  413.     SetMapMode(hDC, uMM);
  414.     return;
  415.     }
  416.  
  417.  
  418.  
  419.  
  420.  
  421. /*
  422.  * CPages::UpdateScrollRanges
  423.  *
  424.  * Purpose:
  425.  *  Reset scrollbar ranges (horizontal and vertical) depending on
  426.  *  the window size and the page size.  This function may remove the
  427.  *  scrollbars altogether.
  428.  *
  429.  * Parameters:
  430.  *  None, but set m_cx, m_cy and size m_hWnd before calling.
  431.  *
  432.  * Return Value:
  433.  *  None
  434.  */
  435.  
  436. void CPages::UpdateScrollRanges(void)
  437.     {
  438.     UINT        cxSB;   //Scrollbar width and height.
  439.     UINT        cySB;
  440.     UINT        cx, cy;
  441.     UINT        dx, dy;
  442.     UINT        u;
  443.     int         iMin, iMax;
  444.     RECT        rc;
  445.     BOOL        fHScroll;
  446.     BOOL        fVScroll;
  447.     BOOL        fWasThere;
  448.  
  449.     GetClientRect(m_hWnd, &rc);
  450.  
  451.     cx=rc.right-rc.left;
  452.     cy=rc.bottom-rc.top;
  453.  
  454.     //Convert dimensions of the image in LOMETRIC to pixels.
  455.     SetRect(&rc, (m_cx+m_xMarginLeft+m_xMarginRight+LOMETRIC_BORDER*2)
  456.         , (m_cy+m_yMarginTop+m_yMarginBottom+LOMETRIC_BORDER*2), 0, 0);
  457.  
  458.     RectConvertMappings(&rc, NULL, TRUE);
  459.  
  460.     dx=rc.left;
  461.     dy=-rc.top;
  462.  
  463.     //Assume that both scrollbars will be visible.
  464.     fHScroll=TRUE;
  465.     fVScroll=TRUE;
  466.  
  467.     /*
  468.      * Determine:
  469.      *  1)  Which scrollbars are needed.
  470.      *  2)  How many divisions to give scrollbars so as to
  471.      *      only scroll as little as necessary.
  472.      */
  473.  
  474.     //Scrollbar dimensions in our units.
  475.     cxSB=GetSystemMetrics(SM_CXVSCROLL);
  476.     cySB=GetSystemMetrics(SM_CYHSCROLL);
  477.  
  478.     //Remove horizontal scroll if window >= cxPage+borders
  479.     if (cx >= dx)
  480.         fHScroll=FALSE;
  481.  
  482.  
  483.     /*
  484.      * If we still need a horizontal scroll, see if we need a vertical
  485.      * taking the height of the horizontal scroll into account.
  486.      */
  487.  
  488.     u=fHScroll ? cySB : 0;
  489.  
  490.     if ((cy-u) >= dy)
  491.         fVScroll=FALSE;
  492.  
  493.     //Check to see if adding a vertical scrollbar necessitates a horz now.
  494.     u=fVScroll ? cxSB : 0;
  495.     fHScroll=((cx-u) < dx);
  496.  
  497.     /*
  498.      * Modify cx,cy to reflect the new client area before scaling
  499.      * scrollbars.  We only affect the client size if there is a
  500.      * *change* in scrollbar status:  if the scrollbar was there but
  501.      * is no longer, then add to the client size; if it was not there
  502.      * but now is, then subtract.
  503.      */
  504.  
  505.     //Change cx depending on vertical scrollbar change
  506.     GetScrollRange(m_hWnd, SB_VERT, &iMin, &iMax);
  507.     fWasThere=(0!=iMin || 0!=iMax);
  508.  
  509.     if (fWasThere && !fVScroll)
  510.         cx+=cxSB;
  511.  
  512.     if (!fWasThere && fVScroll)
  513.         cx-=cxSB;
  514.  
  515.     //Change cy depending on horizontal scrollbar change
  516.     GetScrollRange(m_hWnd, SB_HORZ, &iMin, &iMax);
  517.     fWasThere=(0!=iMin || 0!=iMax);
  518.  
  519.     if (fWasThere && !fHScroll)
  520.         cy+=cySB;
  521.  
  522.     if (!fWasThere && fHScroll)
  523.         cy-=cySB;
  524.  
  525.  
  526.     /*
  527.      * Show/Hide the scrollbars if necessary and set the ranges.  The range
  528.      * is the number of units of the page we cannot see.
  529.      */
  530.     if (fHScroll)
  531.         {
  532.         //Convert current scroll position to new range.
  533.         u=GetScrollPos(m_hWnd, SB_HORZ);
  534.  
  535.         if (0!=u)
  536.             {
  537.             GetScrollRange(m_hWnd, SB_HORZ, &iMin, &iMax);
  538.             u=MulDiv(u, (dx-cx), (iMax-iMin));
  539.             }
  540.  
  541.         SetScrollRange(m_hWnd, SB_HORZ, 0, dx-cx, FALSE);
  542.         SetScrollPos(m_hWnd, SB_HORZ, u, TRUE);
  543.         m_xPos=u;
  544.         }
  545.     else
  546.         {
  547.         SetScrollRange(m_hWnd, SB_HORZ, 0, 0, TRUE);
  548.         m_xPos=0;
  549.         }
  550.  
  551.     if (fVScroll)
  552.         {
  553.         //Convert current scroll position to new range.
  554.         u=GetScrollPos(m_hWnd, SB_VERT);
  555.  
  556.         if (0!=u)
  557.             {
  558.             GetScrollRange(m_hWnd, SB_VERT, &iMin, &iMax);
  559.             u=MulDiv(u, (dy-cy), (iMax-iMin));
  560.             }
  561.  
  562.         SetScrollRange(m_hWnd, SB_VERT, 0, dy-cy, FALSE);
  563.         SetScrollPos(m_hWnd, SB_VERT, u, TRUE);
  564.  
  565.         m_yPos=u;
  566.         }
  567.     else
  568.         {
  569.         SetScrollRange(m_hWnd, SB_VERT, 0, 0, TRUE);
  570.         m_yPos=0;
  571.         }
  572.  
  573.     //Repaint to insure that changes to m_xPos and m_yPos are reflected
  574.     InvalidateRect(m_hWnd, NULL, TRUE);
  575.  
  576.     return;
  577.     }
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587. /*
  588.  * CPages::Print
  589.  *
  590.  * Purpose:
  591.  *  Prints a specified range of pages to a given hDC.  Repeats for
  592.  *  a given number of copies.
  593.  *
  594.  * Parameters:
  595.  *  hDC             HDC to which we print.
  596.  *  pszDoc          LPSTR providing the document name.
  597.  *  dwFlags         DWORD flags from PrintDlg
  598.  *  iPageStart      UINT starting page index (one based)
  599.  *  iPageEnd        UINT ending page index (one based).  Includes this page.
  600.  *  cCopies         UINT number of copies to print.  If PD_COLLATE in
  601.  *                  dwFlags is set, we print multiple copies of each page
  602.  *                  as we cycle through.  Otherwise we cycle multiple times.
  603.  *
  604.  * Return Value:
  605.  *  None
  606.  */
  607.  
  608. BOOL CPages::Print(HDC hDC, LPSTR pszDoc, DWORD dwFlags, UINT iPageStart
  609.     , UINT iPageEnd, UINT cCopies)
  610.     {
  611.     BOOL        fError=FALSE;
  612.     int         iPage, iPageInc;
  613.     int         iUserPage, cPages;
  614.     UINT        iRepeat, cRepeat;
  615.     UINT        iCycle, cCycles;
  616.     UINT        iPageHold=m_iPageCur;
  617.     HWND        hWndT, hWndTop=NULL;
  618.     DLGPROC     pfnDlg;
  619.     ABORTPROC   pfnAbort;
  620.     DOCINFO     di;
  621.  
  622.     //Validate hDC and page ranges
  623.     if (NULL==hDC)
  624.         return FALSE;
  625.  
  626.     if ((PD_PAGENUMS & dwFlags))
  627.         {
  628.         if (-1==iPageStart)
  629.             iPageStart=0;
  630.  
  631.         if (-1==iPageEnd)
  632.             iPageEnd=m_cPages-1;
  633.         }
  634.     else //Can't test PD_ALLPAGES with & since it's defined as 0L
  635.         {
  636.         iPageStart=0;
  637.         iPageEnd=m_cPages-1;
  638.         }
  639.  
  640.     //Arrage number of cycles and repeats depending on cCopies and flags.
  641.     if (PD_COLLATE & dwFlags)
  642.         {
  643.         cCycles=cCopies;
  644.         cRepeat=1;
  645.         }
  646.     else
  647.         {
  648.         cCycles=1;
  649.         cRepeat=cCopies;
  650.         }
  651.  
  652.     //Disable the top window to prevent reentrancy while printing.
  653.     hWndT=m_hWnd;
  654.  
  655.     while (NULL!=hWndT)
  656.         {
  657.         hWndTop=hWndT;
  658.         hWndT=GetParent(hWndT);
  659.         }
  660.  
  661.     EnableWindow(hWndTop, FALSE);
  662.  
  663.     pfnAbort=(ABORTPROC)MakeProcInstance((FARPROC)AbortProc, m_hInst);
  664.     SetAbortProc(hDC, pfnAbort);
  665.  
  666.     g_fCancelPrint=FALSE;
  667.  
  668.     //If these don't work then we'll just live without a dialog.
  669.     pfnDlg=(DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, m_hInst);
  670.     g_hDlgPrint=CreateDialog(m_hInst, MAKEINTRESOURCE(IDD_PRINTING)
  671.         , hWndTop, pfnDlg);
  672.  
  673.  
  674.     //Increment for either direction.
  675.     iPageInc=(iPageStart > iPageEnd) ? -1 : 1;
  676.  
  677.     //Initial entries in dialog box.
  678.     cPages=1+((int)(iPageEnd-iPageStart)*iPageInc);
  679.  
  680.     SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE, 1, (LPARAM)cPages);
  681.     SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, 1, (LPARAM)cRepeat);
  682.  
  683.     di.cbSize=sizeof(DOCINFO);
  684.     di.lpszDocName=pszDoc;
  685.     di.lpszOutput=NULL;
  686.  
  687.     if (StartDoc(hDC, &di) > 0)
  688.         {
  689.         /*
  690.          * Iterate over the pages, repeating each page depending on
  691.          * the copies we want and if we have collate enabled.
  692.          */
  693.  
  694.         for (iCycle=1; iCycle <= cCycles; iCycle++)
  695.             {
  696.             if (PD_COLLATE & dwFlags)
  697.                 SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, iCycle, (LPARAM)cCycles);
  698.  
  699.             //iPageInc controls direction; end of loop controls termination.
  700.             for (iPage=iPageStart; ; iPage+=iPageInc)
  701.                 {
  702.                 iUserPage=1+((iPage-(int)iPageStart)*iPageInc);
  703.  
  704.                 SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE
  705.                     , iUserPage, (LPARAM)cPages);
  706.  
  707.                 m_iPageCur=iPage;   //We restore this later.
  708.  
  709.                 for (iRepeat=1; iRepeat <= cRepeat; iRepeat++)
  710.                     {
  711.                     if (!(PD_COLLATE & dwFlags))
  712.                         {
  713.                         SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE
  714.                             , iRepeat, (LPARAM)cRepeat);
  715.                         }
  716.  
  717.                     StartPage(hDC);
  718.                     Draw(hDC, TRUE, TRUE);
  719.  
  720.                     if (EndPage(hDC) < 0)
  721.                         fError=TRUE;
  722.  
  723.                     if (fError || g_fCancelPrint)
  724.                         break;
  725.                     }
  726.  
  727.                 if (fError || g_fCancelPrint)
  728.                     break;
  729.  
  730.                 //If we just printed the last page, time to quit.
  731.                 if (iPage==(int)iPageEnd)
  732.                     break;
  733.                 }
  734.  
  735.             if (fError || g_fCancelPrint)
  736.                 break;
  737.             }
  738.  
  739.         if (!fError)
  740.             EndDoc(hDC);
  741.         else
  742.             AbortDoc(hDC);
  743.         }
  744.     else
  745.         fError=TRUE;
  746.  
  747.     //Set the page back to what it was before all this started.
  748.     m_iPageCur=iPageHold;
  749.  
  750.     DestroyWindow(g_hDlgPrint);
  751.     SetActiveWindow(hWndTop);
  752.  
  753.     FreeProcInstance((FARPROC)pfnDlg);
  754.     FreeProcInstance((FARPROC)pfnAbort);
  755.     EnableWindow(hWndTop, TRUE);
  756.     DeleteDC(hDC);
  757.  
  758.     return !fError;
  759.     }
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766. /*
  767.  * AbortProc
  768.  *
  769.  * Purpose:
  770.  *  Abort procedure for printing the pages.
  771.  *
  772.  * Parameters:
  773.  *  hDC             HDC on which printing is happening.
  774.  *  iErr            int error code.
  775.  *
  776.  * Return Value:
  777.  *  BOOL            TRUE to continue the print job, FALSE otherwise.
  778.  */
  779.  
  780. BOOL __export FAR PASCAL AbortProc(HDC hDC, int iErr)
  781.     {
  782.     MSG     msg;
  783.  
  784.     while (!g_fCancelPrint && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  785.         {
  786.         if (NULL==g_hDlgPrint || !IsDialogMessage(g_hDlgPrint, &msg))
  787.             {
  788.             TranslateMessage(&msg);
  789.             DispatchMessage(&msg);
  790.             }
  791.         }
  792.  
  793.     return !g_fCancelPrint;
  794.     }
  795.  
  796.  
  797.  
  798.  
  799. /*
  800.  * PrintDlgProc
  801.  *
  802.  * Purpose:
  803.  *  Modeless dialog procedure for the dialog displayed while Patron
  804.  *  is printing pages.
  805.  */
  806.  
  807. BOOL __export FAR PASCAL PrintDlgProc(HWND hDlg, UINT iMsg
  808.     , WPARAM wParam, LPARAM lParam)
  809.     {
  810.     char            szFormat[40];
  811.     char            szOutput[80];
  812.  
  813.     switch (iMsg)
  814.         {
  815.         case WM_INITDIALOG:
  816.             EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_GRAYED);
  817.             return TRUE;
  818.  
  819.         case WM_COMMAND:
  820.             //Cancel button was pressed.
  821.             g_fCancelPrint=TRUE;
  822.             ShowWindow(hDlg, SW_HIDE);
  823.             return TRUE;
  824.  
  825.         case PRINTM_PAGEUPDATE:
  826.             GetDlgItemText(hDlg, ID_PAGESTRING, szFormat, sizeof(szFormat));
  827.             wsprintf(szOutput, szFormat, (UINT)wParam, (UINT)lParam);
  828.             SetDlgItemText(hDlg, ID_CURRENTPAGE, szOutput);
  829.             return TRUE;
  830.  
  831.         case PRINTM_COPYUPDATE:
  832.             GetDlgItemText(hDlg, ID_COPYSTRING, szFormat, sizeof(szFormat));
  833.             wsprintf(szOutput, szFormat, (UINT)wParam, (UINT)lParam);
  834.             SetDlgItemText(hDlg, ID_CURRENTCOPY, szOutput);
  835.             return TRUE;
  836.         }
  837.  
  838.     return FALSE;
  839.     }
  840.